package sf.j2tree.list;

/**
 * Created by ping on 2017-09-11.
 */
public class LinkListImpl<T> implements LinkList<T> {

    private Node<T> head;
    private Node<T> tail;
    private int size = 0;

    public LinkListImpl() {

    }

    private boolean isValid(int index) {
        if (index < 0) {
            throw new IllegalArgumentException("参数不能为负数");
        }
        if (index >= size) {
            throw new IllegalArgumentException("数组越界");
        }
        return true;
    }

    private Node getPrevious(T t) {
        Node node = head;
        for (int i = 0; i < size && node != null; i++) {
            if (node.next != null && node.next.data.equals(t)) {
                return node;
            }
            node = node.next;
        }
        return null;
    }

    private Node getNode(int index) {
        if (isValid(index)) {
            if (isEmpty()) {
                return null;
            }
            Node node = head;
            for (int i = 0; i < size && node != null; i++) {
                if (index == i) {
                    return node;
                }
                node = node.next;
            }
        }

        return null;
    }

    @Override
    public boolean isEmpty() {
        return size > 0 ? false : true;
    }

    @Override
    public int length() {
        return size;
    }

    @Override
    public T get(int index) {
        if (isEmpty()) {
            return null;
        }
        if (isValid(index)) {
            Node node = getNode(index);
            if (node != null) {
                return (T) node.data;
            }
        }
        return null;
    }

    @Override
    public T replace(int index, T t) {
        if (isEmpty()) {
            return null;
        }
        if (isValid(index)) {
            Node node = getNode(index);
            Object old = node.data;
            node.data = t;
            return (T) old;
        }
        return null;
    }

    @Override
    public boolean add(int index, T t) {
        if (isEmpty()) {
            this.head = this.tail = new Node(t, null);
            size++;
            return true;
        }
        if (isValid(index)) {
            Node node = getNode(index);
            if (node != null) {
                Node newNode = new Node(t, node.next);
                node.next = newNode;
                if (index == this.size) {
                    this.tail = newNode;
                }
                size++;
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean add(T t) {
        if (isEmpty()) {
            this.head = this.tail = new Node(t, null);
            size++;
            return true;
        } else {
            Node temp = this.tail;
            this.tail = new Node<>(t, null);
            temp.next = this.tail;
            size++;
            return true;
        }
    }

    @Override
    public boolean remove(int index) {
        if (isEmpty()) {
            return false;
        }
        if (isValid(index)) {
            if (index == 0) {
                this.head = this.head.next;
                size--;
                return true;
            } else {
                Node previous = getNode(index - 1);
                Node node = getNode(index);
                previous.next = node.next;
                if (node.next == null) {
                    this.tail = previous;
                }
                size--;
                return true;
            }

        }
        return false;
    }

    @Override
    public boolean remove(T t) {
        int index = indexOf(t);
        if (index > 0) {
            Node previous = getPrevious(t);
            Node node = getNode(index);
            if (previous == null) {
                this.head = this.head.next;
                size--;
                return true;
            } else {
                previous.next = node.next;
                size--;
                if (node.next == null) {
                    this.tail = previous;
                }
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean removeAll() {
        this.head = this.tail = null;
        this.size = 0;
        return true;
    }

    @Override
    public void clear() {
        this.head = this.tail = null;
        this.size = 0;
    }

    @Override
    public boolean contains(T t) {
        if (indexOf(t) >= 0) {
            return true;
        }
        return false;
    }

    @Override
    public int indexOf(T t) {
        Node node = head;
        for (int i = 0; i < size && node != null; i++) {
            if (node.data.equals(t)) {
                return i;
            }
            node = node.next;
        }
        return -1;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder("[");
        Node node = this.head;
        for (int i = 0; i < size && node != null; i++) {
            sb.append(node.data).append(", ");
            node = node.next;
        }
        if (this.size > 0) {
            sb.deleteCharAt(sb.length() -1);
            sb.deleteCharAt(sb.length() -1);
        }

        sb.append("]");
        return sb.toString();
    }

    private class Node<T> {
        T data;
        Node<T> next;
        public Node(T data, Node<T> next) {
            this.data = data;
            this.next = next;
        }
    }


    public static void main(String[] args) {
        LinkList<Integer> list = new LinkListImpl<>();
        int mm = 0;
        list.add(mm++);
        list.add(mm++);
        list.add(mm++);
        list.add(mm++);
        list.add(mm++);
        list.add(mm++);
        System.out.println(list);
        list.add(3, 59);
        System.out.println(list);
        System.out.println(list.indexOf(5));
        System.out.println(list.replace(6, 100));
        System.out.println(list);
        System.out.println(list.remove(new Integer(4)));
        System.out.println(list);
        list.add(523);
        System.out.println(list);
        System.out.println(list.contains(523));
    }
}
